﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using Common;

namespace Host
{
    /// <summary>
    /// UDP接口相关内容
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public delegate byte[] UDPInterface(byte[] data);

    public class UDPData
    {
        public byte[] Data { get; set; }

        public IPEndPoint Address { get; set; }
    }

    public class UDPServerComponents : IComponents
    {
        private bool _runing = false;
        private Thread _thread = null;

        private RouteData<UDPInterface> route_data = new RouteData<UDPInterface>();

        public RouteData<UDPInterface> RouteData { get { return route_data; } }

        private int port = 11001;
        public int Port { get { return port; } set { port = value; } }

        public Dictionary<string, string> GetUDPHeaders(byte[] data)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();

            MemoryStream ms = new MemoryStream(data);
            StreamReader sr = new StreamReader(ms);

            while (sr.Peek() > 0)
            {
                var line = sr.ReadLine();
                if (string.IsNullOrEmpty(line))
                    break;

                int index = line.IndexOf(':');

                if (index == -1)
                    continue;

                string head = line.Substring(0, index);
                string body = line.Substring(index + 1, line.Length - index - 1);

                dic.Add(head, body);
            }

            sr.Close();
            ms.Close();

            return dic;
        }

        public string GetUDPBody(byte[] data)
        {
            string body = string.Empty;

            MemoryStream ms = new MemoryStream(data);
            StreamReader sr = new StreamReader(ms);

            while (sr.Peek() > 0)
            {
                var line = sr.ReadLine();
                if (string.IsNullOrEmpty(line))
                    break;
            }

            body = sr.ReadToEnd();

            sr.Close();
            ms.Close();

            return body;
        }

        public string GetHeadValue(byte[] data, string key)
        {
            var mapping = GetUDPHeaders(data);
            return mapping.ContainsKey(key) ? mapping[key] : string.Empty;
        }

        public string GetRouteKey(byte[] data)
        {
            return GetHeadValue(data, "Action");
        }

        public override void OnEnter()
        {
            base.OnEnter();

            _runing = true;
            _thread = new Thread(() =>
            {
                IPEndPoint ip = new IPEndPoint(IPAddress.Any, port);
                UdpClient udpclient = new UdpClient(ip);
                IPEndPoint ipendpoint = new IPEndPoint(IPAddress.Any, 0);

                udpclient.Client.ReceiveTimeout = 10000;

                while (_runing)
                {
                    if (udpclient.Available > 0)
                    {
                        try
                        {
                            byte[] bytes = udpclient.Receive(ref ipendpoint);
                            ThreadPool.QueueUserWorkItem((obj) =>
                            {
                                try
                                {
                                    UDPData udp_data = obj as UDPData;
                                    if (udp_data == null)
                                        return;

                                    Console.WriteLine(udp_data.Address.ToString() + "\r\n" + Encoding.UTF8.GetString(udp_data.Data));

                                    var route_key = GetRouteKey(udp_data.Data);

                                    if (string.IsNullOrEmpty(route_key))
                                        return;

                                    var handle = RouteData.FindValue(route_key);
                                    if (handle == null)
                                        return;

                                    var result = handle(udp_data.Data);

                                    udpclient.Send(result, result.Length, udp_data.Address);
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine(ex.Message);
                                }

                            }, new UDPData { Data = bytes, Address = new IPEndPoint(ipendpoint.Address, ipendpoint.Port) });
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                    else
                    {
                        Thread.Sleep(100);
                    }
                }
            });
            _thread.IsBackground = true;
            _thread.Start();
        }

        public override void OnExit()
        {
            base.OnExit();

            _runing = false;
            while (_thread.ThreadState == ThreadState.Running)
                ;
        }
    }
}
